﻿using DeltaGroup.WheelOfJeopardy.GameManager;
using DeltaGroup.WoJ.Tests.Stub;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using DeltaGroup.WheelOfJeopardy.Model;
using System.Collections.Generic;
using DeltaGroup.WheelOfJeopardy.UI.Events;
using Moq;

namespace DeltaGroup.WoJ.Tests.GameManagerTests
{
    /// <summary>
    ///This is a test class for FinalJeopardyRoundTest and is intended
    ///to contain all FinalJeopardyRoundTest Unit Tests
    ///</summary>
    [TestClass()]
    public class FinalJeopardyRoundTest
    {
        private Mock<IFinalJeopardyUIManager> _uiManager;
        private Mock<IChallengeManager> _challengeManager;
        private StubGameSettings _gameSetting;
        private FinalJeopardyRound _round;
        private Challenge _challenge;
        private List<Contestant> _contestants;

        [TestInitialize]
        public void Initialize()
        {
            _uiManager = new Mock<IFinalJeopardyUIManager>();
            _challengeManager = new Mock<IChallengeManager>();
            _gameSetting = new StubGameSettings();
            _contestants = new List<Contestant>()
                               {
                                   new Contestant(){Name = "Terry", FreeTurnCount = 0, IsPlaying = false, Score = 300},
                                   new Contestant(){Name = "Mike", FreeTurnCount = 0, IsPlaying = false, Score = 300},
                                   new Contestant(){Name = "Kyle", FreeTurnCount = 0, IsPlaying = false, Score = 300}
                               };
            _challenge = new Challenge(){Category = "test category", Prompt = "test prompt"};
            

            _round = new FinalJeopardyRound(_gameSetting, _challenge, _contestants, DifficultyLevel.Easy) { UIManager = _uiManager.Object, ChallengeManager = _challengeManager.Object };
            _round.Start();
        }
        [TestMethod]
        public void On_Start_Set_First_Contestant_To_Play()
        {
            Assert.IsTrue(_contestants[0].IsPlaying);
        }
        [TestMethod]
        public void On_Start_Set_First_Contestan_To_Wager()
        {
            _uiManager.Verify(x => x.PromptForWager(_contestants[0].Score));
        }
        [TestMethod]
        public void Ask_For_Response_After_Receiving_Wager()
        {
            _uiManager.Raise(x => x.WagerReceived += null, new WagerReceivedEventArgs(100));

            _uiManager.Verify(x => x.PromptForResponse(_challenge, 60));
        }
        [TestMethod]
        public void Award_Wager_Point_On_Correct_Response()
        {
            _challengeManager.Setup(x => x.IsResponseCorrect(It.IsAny<DifficultyLevel>(), It.IsAny<Challenge>(), It.IsAny<string>())).Returns(true);
            
            PlayTurn(100);

            Assert.AreEqual(400, _contestants[0].Score);
           
        }

        private void PlayTurn(int wager)
        {
            _uiManager.Raise(x => x.WagerReceived += null, new WagerReceivedEventArgs(wager));
            _uiManager.Raise(x => x.ChallengeResponseReceived += null, new ChallengeResponseReceivedEventArgs("test"));
        }

        [TestMethod]
        public void Deduct_Wager_Point_On_Incorrect_Response()
        {
            _challengeManager.Setup(x => x.IsResponseCorrect(It.IsAny<DifficultyLevel>(), It.IsAny<Challenge>(), It.IsAny<string>())).Returns(false);
            
            PlayTurn(100);

            Assert.AreEqual(200, _contestants[0].Score);
        }
        [TestMethod]
        public void Move_Onto_Next_Contestant_If_Time_Expired()
        {
            _uiManager.Raise(x => x.ResponseTimerExpired += null, new EventArgs());

            Assert.IsFalse(_contestants[0].IsPlaying);
            Assert.IsTrue( _contestants[1].IsPlaying);
        }
        [TestMethod]
        public void No_Point_Loss_If_Time_Expired()
        {
            _uiManager.Raise(x => x.ResponseTimerExpired += null, new EventArgs());

            Assert.AreEqual(300, _contestants[0].Score);
        }
        [TestMethod]
        public void Ends_Round_When_All_Contestants_Participated()
        {
            var roundEnded = false;
            _round.Finished += (sender, args) => { roundEnded = true; };

            for (int i = 0; i < 3; i++)
            {
                PlayTurn(100);
            }

            Assert.IsTrue(roundEnded);
        }
        [TestMethod]
        public void Only_Contestants_With_Score_Greater_Or_Equal_To_100_Can_Participate()
        {
            var contestants = new List<Contestant>(){
                                   new Contestant(){Name = "Terry", FreeTurnCount = 0, IsPlaying = false, Score = 300},
                                   new Contestant(){Name = "Mike", FreeTurnCount = 0, IsPlaying = false, Score = 100},
                                   new Contestant(){Name = "Kyle", FreeTurnCount = 0, IsPlaying = false, Score = 0}
                               };
            var round = new FinalJeopardyRound(_gameSetting, _challenge, contestants, DifficultyLevel.Easy);

            Assert.AreEqual(2, round.ParticipatingContestants.Count);
        }
    }
}
